import type { Ref, UnwrapRef } from 'vue'
import { throttle } from 'lodash-es'

interface RequestOptions {
  /** 是否立即执行 */
  immediate?: boolean
  /** 节流时间，单位毫秒，默认 300ms */
  throttleTime?: number
}

/**
 * useAutoRequest 是请求的再次封装，类似于 react-query 中的 userQuery
 * 核心使用场景，就前端而言，分页查询用的比较多，其他嘛用得还是比较少
 * @param queryFn 一个执行异步请求的函数，返回一个包含响应数据的 Promise
 * @param queryKey 请求的唯一标识，用于监听参数变化，重新发起请求
 * @param options 包含请求选项的对象 {immediate, throttleTime}。
 * @param callback 回调函数，在请求成功或失败时调用，参数为响应数据和错误信息。
 * @param options.immediate 是否立即执行请求，默认为false。
 * @param options.throttleTime 节流时间，单位毫秒，默认 300ms。
 * @returns 返回一个对象{loading, error, data, run}，包含请求的加载状态、错误信息、响应数据和手动触发请求的函数。
 */
export default function useAutoRequest<T>({ queryKey, options = { immediate: false, throttleTime: 300 }, queryFn, callback }: {
  queryKey?: Ref<T>[]
  options?: RequestOptions
  queryFn: () => Promise<ResData<T>>
  callback?: (data, error) => void
}) {
  const loading = ref(false)
  const error = ref(false)
  const data = ref() // 不做类型定义，让 ts 默认推导
  const run = async () => {
    loading.value = true
    return queryFn()
      .then((res) => {
        data.value = res.data as UnwrapRef<T>
        error.value = false
        return data.value
      })
      .catch((err) => {
        error.value = err
        // throw err
      })
      .finally(() => {
        loading.value = false
        callback && callback(data.value, error.value)
      })
  }

  // 创建节流版本的 run 函数
  // leading: true：表示在节流时间窗口的开始时就执行一次函数
  // trailing: true：表示在节流时间窗口结束时执行最后一次调用的函数
  const throttledRun = throttle(run, options.throttleTime || 300, { leading: true, trailing: true })

  // 监听 queryKey 变化，使用节流函数重新发起请求
  queryKey && watch([...queryKey], () => {
    throttledRun()
  })

  options.immediate && run()

  return { loading, error, data, run }
}
